# encoding:utf-8

import random
import re
import threading
import requests
import plugins
import pandas as pd
import numpy as np
# 桥接消息
from bridge.context import Context, ContextType
from bridge.reply import Reply, ReplyType
from channel.chat_message import ChatMessage
from plugins.plugin import Plugin
# 引入控制台打印的函数
from common.log import logger
# 从插件中导入所有函数
from plugins import *
# 获取全局配置文件信息
from config import conf
# 调用直接回复消息的函数
from lib import itchat
from PIL import Image
import openpyxl

# 定义一些可能的回复消息
messages = [
            "你好呀！",
            "很高兴见到你。",
            "你看看你，这大风大雪的，还要这么拼命，一定也是为了那个玩意儿。",
            "今天天气不错呢。",
            "小神是黑风山的土地，在此处候你多时了。",
            "有什么好玩的事情分享吗？",
            "加油，你是最棒的！",
            "我勒个豆，你居然跟我打招呼了",
            "来着何人，敢来此处扰我清修",
            "欸，又是只猴子？",
            "施主，不如放下棍棒，也同我学点佛法 如何？",
            "入了此番轮回，就别想再轻易涅槃。",
            "蠢狗，放肆，还不退下。",
            "糊狲啊糊狲，我本不想与你这个手下败将再战一场。",
            "这里除了我，没人配与他单挑。",
            "泼猴，吃吾一刃!",
            "斗战胜佛……你可知这长生不老的佛位，有多少人求而不得?",
            "可悲的取经人呐，只要心中还有放不下的偶像，终有一天，它将化为修行路上无解的业障。",
            "踏遍苦难尽蹉跎，取经之人尤可悲。\n\
                口声声情怀大义，心晃晃世俗名利。\n\
                    唱得定命不由天，笃以为己天命选。\n\
                        在这无尽的轮回中，每一个选择都是新的开始，也是旧的终结。\n\
                            有些事情不看对错美丑，更不论强弱输赢，更是机缘编织的宿命。\n",
            "既见未来，为何不拜。"
]


# 注册插件的说明信息
@plugins.register(
    name = "GroupChat", # 插件名
    desc = "定制化的群组管理插件", # 本插件描述
    version = "1.0", # 版本
    author="姜子牙", # 作者
    desire_priority= 800, #优先级
)

class GroupChat(Plugin):

    # 插件初始化函数
    def __init__(self):
        super().__init__()
        try:
            # 加载当前插件配置文件：config.json
            self.config = super().load_config()
            if not self.config: 
                # 配置文件不存在加载默认配置文件
                self.config = self._load_config_template()
            
            # 往全局配置文件中加入新的配置文件
            # 插件中的群名和全局文件对比:这里的=是指向了配置文件的地址
            self.Global_group_name = conf().get("group_name_white_list", [])
            self.group_name = self.config.get("group_name", {})

            s = []
            for group_name in self.group_name:
                if group_name not in self.Global_group_name:
                    s += [group_name]
                    self.Global_group_name.append(group_name)
            logger.info("[定制化群管] 新增群名: {}".format(s))
                    
            s = []
            for group_name in self.Global_group_name:
                if group_name not in self.group_name: # 判断全局配置文件群名是否在插件配置群名中
                    s += [group_name]
                    self.Global_group_name.remove(group_name) # 从全局配置中删除
            logger.info("[定制化群管] 移除群名: {}".format(s))
            logger.info("[定制化群管] 加载群名白名单: {}".format(self.Global_group_name))

            a = conf().update({"group_name_white_list": self.Global_group_name})
            logger.info("[定制化群管] 更新全局配置文件: {}".format(a))


            # 在全局配置文件group_chat_keyword中加入新的配置文件
            self.Global_group_keyword = conf().get("group_chat_keyword", [])
            self.group_keyword = self.config.get("group_keyword", {})
            # 新增关键字
            # 往全局配置文件中加入新的配置文件就可以实现群关键词的配置
            s = []
            for group_keyword in self.config.get("group_keyword", {}) :
                if group_keyword not in self.Global_group_keyword:
                    s += [group_keyword]
                    self.Global_group_keyword.append(group_keyword)
            logger.info("[定制化群管] 添加关键字: {}".format(s))

            # 移除关键字
            s = []
            for group_keyword in self.Global_group_keyword:
                if group_keyword not in self.config.get("group_keyword", {}): # 判断全局配置文件群名是否在插件配置群名中
                    s += [group_keyword]
                    self.Global_group_keyword.remove(group_keyword) # 从全局配置中删除
            logger.info("[定制化群管] 移除关键字: {}".format(s))
            # 触发自动回复的关键字
            logger.info("[定制化群管] 加载群关键字白名单: {}".format(self.Global_group_keyword))
            
            # 获取插件中设定的群关键词
            self.group_keyword = self.config.get("group_keyword", {})

            self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context # 注册处理context的函数

            logger.info("[定制化群管] 已初始化")
        except Exception as e:
            logger.error("[定制化群管] 插件初始化失败，请检查配置文件{}".format(e))
    


    # EventContext(Event事件类型, {'channel' : 消息channel, 'context': Context, 'reply': Reply})
    def on_handle_context(self, e_context: EventContext):
        # 将收到的消息包装成：群或私聊消息对象
        msg: ChatMessage = e_context["context"]["msg"]

        logger.info("[定制化群管] 收到消息: {}".format(msg.content))

        # 从来自的消息获取群名称
        group_name = msg.from_user_nickname
        group_keyword = msg.content
        message = e_context["context"].content

        context = e_context["context"]

        # 如果收到的消息是图片就什么都不处理——或者对图像进行文本识别
        if msg.ctype == ContextType.IMAGE:
            
            e_context.action = EventAction.BREAK_PASS
        else:
            url='./plugins/GroupChat/groupChat.xlsx'
            # 读取Excel文件
            df = pd.read_excel(url,sheet_name='Sheet1',engine='openpyxl')
            logger.info('[定制化群管] 关键词：{}'.format(df['target_group_keyword'].values))
            logger.info('[定制化群管] 模糊关键词：{}'.format(df['group_chat_keyword'].values))
            # 在此处将模糊关键词写入全局配置文件
            # 获取关键词数组
            keywords = df['group_chat_keyword'].values
            # 准备更新后的关键词列表
            updated_keywords = getKeyword(keywords)
            
            # 在全局配置文件group_chat_keyword中加入新的配置文件
            Global_group_keyword = conf().get("group_chat_keyword", [])
            setGlobal_keyword(updated_keywords,Global_group_keyword)
            print('最终：{}'.format(Global_group_keyword))

            # 将表格中的模糊匹配关键词以及模糊匹配的群名和完全匹配的群名称设置到全局配置文件config中
            df2 = pd.read_excel(url,sheet_name='Sheet2',engine='openpyxl')
            logger.info('[定制化群管] 开启回复的群名：{}'.format(df2['group_name_white_list'].values))
            logger.info('[定制化群管] 模糊匹配的群名：{}'.format(df2['group_name_keyword_white_list'].values))

            # 获取开启了回复的群名
            group_names = df2['group_name_white_list'].values
            # 准备更新后的关键词列表
            updated_group_names = getKeyword(group_names)
            Global_group_name = conf().get("group_name_white_list", [])
            setGlobal_keyword(updated_group_names,Global_group_name)
            print('最终群名：{}'.format(Global_group_name))

            # 获取开启回复的模糊匹配群名
            group_name_keywords = df2['group_name_keyword_white_list'].values
            # 准备更新后的关键词列表
            updated_group_name_keywords = getKeyword(group_name_keywords)
            Global_group_name_keyword = conf().get("group_name_keyword_white_list", [])
            setGlobal_keyword(updated_group_name_keywords,Global_group_name_keyword)
            print('最终模糊匹配的群名：{}'.format(Global_group_name_keyword))
            print(group_name)

            # 如果设置了模糊匹配的群名白名单
            if Global_group_name_keyword != []:
                # 遍历配置的群名
                for keyword_name in Global_group_name_keyword:
                    # 目标群名中查找模糊匹配的群名
                    if group_name.find(keyword_name) != -1:
                        match = re.search(keyword_name, group_name) # 从当前群聊名中获取匹配到的关键字
                        keyword_name = match.group()
                        print(match.group())
                        group_name = keyword_name
                        break
                    

            # 句中含关键字的回复————这里需要提出关键字，不然会直接调用大模型回复
            if Global_group_keyword != []:
                # 遍历配置的关键字
                for keyword in Global_group_keyword:
                    # 如果找到，返回位置，否则返回 -1
                    # 消息中包含关键字
                    if message.find(keyword) != -1:
                        match = re.search(keyword, message)
                        keyword = match.group() # 获取当前问题中的关键字
                        message = keyword
                        break

            # 设置文件根目录
            root_dir = os.path.dirname(os.path.abspath(__file__))
            print('根目录：',root_dir)

            # 首先检查是否存在空的target_group并且消息匹配
            # 或者群名匹配模糊群名
            empty_target_group_result = df.query('(target_group.isna() | target_group == "") and target_group_keyword == @message')['message']
            # 群名不匹配但关键词匹配
            if not empty_target_group_result.empty:
                result = empty_target_group_result.values[0]
                print(result)
                reply = Reply() # 创建回复对象
                # 对回复的消息进行判断是否为路径消息
                if "myImages" in result:
                    reply.type = ReplyType.IMAGE
                    result = setImgs_and_Files(root_dir,result)
                elif "myFiles" in result:
                    reply.type = ReplyType.FILE
                    result = setImgs_and_Files(root_dir,result)
                else:
                    reply.type = ReplyType.TEXT
                reply.content = result
                e_context["reply"] = reply
                e_context.action = EventAction.BREAK_PASS
                
            else:
                pattern1 = f'(?:^|、){group_name}(?:、|$)'
                pattern2 = f'(?:^|、){message}(?:、|$)'
                # 再检查特定群聊且消息匹配
                # 根据模糊匹配群聊名进行查找对应的消息
                specific_group_result = df[df['target_group'].str.contains(pattern1, regex=True) & (df['target_group_keyword'].str.contains(pattern2, regex=True))]['message']
                # 群名和关键词都匹配
                if not specific_group_result.empty:
                    result = specific_group_result.values[0]
                    print(result)
                    reply = Reply() # 创建回复对象
                    # 对回复的消息进行判断是否为路径消息
                    if "myImages" in result:
                        reply.type = ReplyType.IMAGE
                        result = setImgs_and_Files(root_dir,result)
                    elif "myFiles" in result:
                        reply.type = ReplyType.FILE
                        result = setImgs_and_Files(root_dir,result)
                    else:
                        reply.type = ReplyType.TEXT
                    reply.content = result
                    e_context["reply"] = reply
                    e_context.action = EventAction.BREAK_PASS
                else:
                    # 群名称不匹配但关键词匹配
                    other = df.query('target_group != @group_name and target_group_keyword == @message')['message']
                    if not other.empty:
                        print('请充值')
                        reply = Reply() # 创建回复对象
                        reply.type = ReplyType.TEXT # 设置默认回复类型
                        reply.content = '当前群聊未授权，\n请联系机器人管理员进行授权使用\n管理员微信：1821045567'
                        e_context["reply"] = reply
                        e_context.action = EventAction.BREAK_PASS
                    else:
                        # 都不匹配
                        print('调用大模型')
                        e_context.action = EventAction.CONTINUE
        
        
        # 句中含关键字的回复————这里需要提出关键字，不然会直接调用大模型回复
        if self.group_keyword != []:
            # 遍历配置的关键字
            for keyword in self.group_keyword:
                # 如果找到，返回位置，否则返回 -1
                # 消息中包含关键字
                if message.find(keyword) != -1:
                    match = re.search(keyword, message)
                    keyword = match.group() # 获取当前问题中的关键字
                    # 根据关键字给出回复
                    if keyword == "在吗":
                        # 提前创建回复对象
                        reply = Reply() # 创建回复对象
                        reply.type = ReplyType.TEXT # 设置默认回复类型
                        reply.content = "不在"
                        e_context["reply"] = reply
                        e_context.action = EventAction.BREAK_PASS  # 事件结束，并跳过处理context的默认逻辑
                        break
                    
      
        # 提前创建回复对象
        reply = Reply() # 创建回复对象
        reply.type = ReplyType.TEXT # 设置默认回复类型

        
        # 以下消息是通过@机器人触发的
        if message == "Hi":
            
            reply.content = random.choice(messages)
            e_context["reply"] = reply
            e_context.action = EventAction.BREAK_PASS  # 事件结束，并跳过处理context的默认逻辑
            # e_context.action = EventAction.BREAK  # 事件结束，进入默认处理逻辑，一般会覆写reply

    # 加载配置信息
    def _load_config_template(self):
        logger.debug("[定制化群管] 该配置文件“config.json”不存在, 使用默认配置文件config.json.template")
        try:
            plugin_config_path = os.path.join(self.path, "config.json.template")
            if os.path.exists(plugin_config_path):
                with open(plugin_config_path, "r", encoding="utf-8") as f:
                    plugin_conf = json.load(f)
                    return plugin_conf
        except Exception as e:
            logger.exception(e)


# 添加（将表格中的关键词添加到全局配置文件中）
def add(updated_keywords,Global_group_keyword):
    key=[]
    for keyword in updated_keywords:
        if keyword not in Global_group_keyword:
            key+=[keyword]
            Global_group_keyword.append(keyword)
    print('新增：',key)
# 移除(从全局配置文件中，移除不在表格中的关键词)
def remove(updated_keywords,Global_group_keyword):
    key=[]
    for keyword in Global_group_keyword:
        if keyword not in updated_keywords: # 判断全局配置文件群名是否在表格配置群名中，以表格为主
            key+=[keyword]
            Global_group_keyword.remove(keyword) # 从全局配置中删除
    print('移除：',key)

def setGlobal_keyword(updated_keywords,Global_group_keyword):
    add(updated_keywords,Global_group_keyword)
    remove(updated_keywords,Global_group_keyword)

# 处理表格中带、和nan的关键词
def getKeyword(keywords):
    updated_keywords = []
    for keyword in keywords:
        if keyword is not np.nan and '、' in keyword:
            sub_keywords = keyword.split('、')
            updated_keywords.extend(sub_keywords)
        elif keyword is not np.nan:
            updated_keywords.append(keyword)
    print('处理后的关键词：{}'.format(updated_keywords))
    return updated_keywords

# 设置要发送的图片或文件的路径
def setImgs_and_Files(root_dir,result):
    # 对图片路径进行拼接
    full_path = os.path.join(root_dir, result)
    # 判断拼接后的路径是否有后缀名
    parts = result.split('.')
    if len(parts) > 1: # 如果有后缀名
        file_extension = parts[-1] # 获取文件后缀名
        logger.info("文件路径：%s", full_path)
        return full_path # 返回拼接后的路径
    else: # 如果没有后缀名,则代表输入的是文件夹，则遍历文件夹，随机选择一个文件
        if "myImages" in result:
            extensions = ['.png', '.jpg'] # 设置支持的图片格式
        else:
            extensions = ['.mp4','.docx','.doc','.doc','.xlsx'] # 设置支持的文档格式
        file_paths = [os.path.join(root, f) for root, _, files in os.walk(full_path) for f in files if any(f.endswith(ext) for ext in extensions)]
        logger.info("文件路径：%s", file_paths)
        return random.choice(file_paths) # 随机选择一个文件路径返回